---@module logfile
-- 用于将日志存放到文件系统中，可以供触摸屏或后台端查看
-- 日志包括 操作记录(opera)，智能方案(smart)，异常记录(exec)，系统日志(sys) 4个部分，分4个文件保存
-- 每种日志最多保存50条
-- item 格式为 {time = }

require "log"
require "tool"
require "config"
require "io"
module(..., package.seeall)
local MAX_ITEM = 50 -- 最多日志记录条数

local logPath =  "/logFile.log" --设备日志

local function init()
    if io.exists(logPath) == false then
        local empty = { item = {} }
        io.writeFile(logPath, json.encode(empty))
    end
end


--开机时先从文件系统读取
init()

-- 将data保存到文件系统中
---@param logfile string
local function save(logfile)
    local jsondata = json.encode(logfile)
    io.writeFile(logPath, jsondata)
end

---@param logEnt LogEntity
local function addLog(logEnt)
    local str = io.readFile(logPath)
    local dat, res, _ = json.decode(str)
    if res then
        local num = #dat.item
        if num < MAX_ITEM then
            dat.item[num + 1] = logEnt
        else
                -- 删除第一条
            table.remove(dat.item, 1)
            dat.item[MAX_ITEM] = logEnt
        end
        save(dat)
    end
end

--post回调函数
local function cbFnc(result, prompt, head, body)
    local json_data, ok = json.decode(body)
    if result then
        if ok and json_data.status == 0 then
            sys.publish("POST_LOG", "ok")
            return
        end
    end
    sys.publish("POST_LOG", "failed")
end

-- 用于智能提示
---@class LogEntity
---@field tag string "sys 或 opera等"
---@field parm string "xxx#xxx#xx 等参数罗列"
---@field time string "2020 等参数罗列"


--向服务器同步消息
---@param loglist LogEntity[]
local function postLogList(loglist)
    local body = json.encode(loglist)
    log.info("sendlog body:",body)
    http.request("POST", config.POSTLOG_URL.."?imei="..misc.getImei(), nil, {
        ["Content-Type"] = "application/json;charset=utf-8",
    }, body, 10000, cbFnc)
end

-- 发送一条日志记录
---@return LogEntity
local function postLogOne(tag,...)
    local arg={...}    --> arg 为一个表，局部变量
    local parm = ""
    for i,v in ipairs(arg) do
        parm = parm..tostring(v).."#" -- 参数罗列分割符
    end
    local body = {
        [1] = {
            tag = tag,
            parm = parm,
            time = tool.getTimeStr()
        }
    }
    postLogList(body)
    return body[1]
end

-- 添加操作日志
---@param msg string
function addOperaLog(...)
    ---@type LogEntity
    local logEnt = postLogOne("opera", ...)
    local result, data = sys.waitUntil("POST_LOG", 15000)
    --如果post到服务器失败，就将该条log保存到本地
    if not result or data == "failed" then
        addLog(logEnt)
    end
end


-- 添加系统记录日志
---@param msg string
function addSyscLog(...)
    local logEnt = postLogOne("sys", ...)
    local result, data = sys.waitUntil("POST_LOG", 15000)
    --如果post到服务器失败，就将该条log保存到本地
    if not result or data == "failed" then
        addLog(logEnt)
    end
end

-- 添加特殊日志,失败不保存本地做同步
function addExtraLog(...)
    postLogOne("ext", ...)
end

 --建立日志同步任务
sys.taskInit(function()
    while true do
        sys.wait(300000)
        local logStr = io.readFile(logPath)
        local dat, res, _ = json.decode(logStr)
        if res then
            log.info("LOG_SYNC","LOG nums="..#dat.item)
            if #dat.item > 0 then
                local toPost = {}
                for i = 1, 10 do
                    if #dat.item > 0 then
                        table.insert(toPost,dat.item[1])
                        table.remove(dat.item,1)
                    else
                        break
                    end
                end
                --同步日志
                postLogList(toPost)
                local result, data = sys.waitUntil("POST_LOG", 15000)
                if result and data == "ok" then
                    save(dat)
                end
            end
        end
        logStr,dat = nil, nil
        collectgarbage("collect")
    end
end)